using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Timers;
using System.Reflection;
using SpoonCore.Storage.Item;

namespace SpoonCore.Storage
{
	public class Storage<T> : IStorage where T : AbstractStorageItem, new()
	{
		private readonly FileStream _stream;
		private readonly SortedList<SpoonIdentifier, T> _buffer = new SortedList<SpoonIdentifier, T>();
		private readonly Timer _storeTimer = new Timer(10 * 1000);

		internal Storage(string dir)
		{
			_stream = new FileStream(dir + typeof(T).FullName.GetHashCode() + ".db", FileMode.OpenOrCreate);

			_storeTimer.Elapsed += _storeTimer_Elapsed;
			_storeTimer.Start();

			Load();
		}

		private void _storeTimer_Elapsed(object sender, ElapsedEventArgs e)
		{
			Flush();
		}

		private void Load()
		{
			_stream.Position = 0;
			BinaryReader br = new BinaryReader(_stream);
			while (_stream.Position < _stream.Length)
			{
				T item = new T();
				int len = br.ReadInt32();
				byte[] data = br.ReadBytes(len);
				item.SetBaseBytes(data);

				len = br.ReadInt32();
				data = br.ReadBytes(len);
				item.SetBytes(data);
				
				_buffer.Add(item.Id, item);
			}
		}

		internal void Flush()
		{
			_stream.SetLength(0);
			BinaryWriter bw = new BinaryWriter(_stream);
			foreach (KeyValuePair<SpoonIdentifier, T> pair in _buffer)
			{
				byte[] buf =pair.Value.GetBaseBytes();
				bw.Write(buf.Length);
				bw.Write(buf);
				buf = pair.Value.GetBytes();
				bw.Write(buf.Length);
				bw.Write(buf);
			}
		}

		public T this[SpoonIdentifier id]
		{
			get
			{
				if (_buffer.ContainsKey(id)) return _buffer[id];
				else return null;
			}
			set
			{
				if (_buffer.ContainsKey(id)) _buffer[id] = value;
				else _buffer.Add(id, value);
			}
		}

		public void Remove(SpoonIdentifier id)
		{
			_buffer.Remove(id);
		}

		public void Add(T item)
		{
			this[item.Id] = item;
		}
	}
}
